import * as Cesium from 'cesium'
import type { CustomDataSource, Entity, Color } from 'cesium'

interface TyphoonTrack {
  typhoonPoints: Cesium.CustomDataSource
  typhoonLineEntity: Cesium.Entity
}

interface TyphoonForeastTrack {
  typhoonForeastPoints: Cesium.CustomDataSource
  typhoonForeastLines: Cesium.CustomDataSource
}

export default class Typhoon {
  public name: string
  private _currentPointObj: PointObj | null = null
  private _typhoonData: TyphoonData | null
  private _windCircleEntity: Entity[] = []
  private _intervalId: number | null = null
  private _typhoonTrack: TyphoonTrack | null
  private _typhoonForeastTrack: TyphoonForeastTrack | null

  constructor(typhoonData: TyphoonData) {
    this.name = typhoonData.ename
    this._typhoonData = typhoonData
    this._typhoonTrack = this._addTyphoonPointsAndLine()
    this._typhoonForeastTrack = this._addTyphoonForeastPoints()
  }

  public get typhoonTrack() {
    return this._typhoonTrack
  }

  public get typhoonForeastTrack() {
    return this._typhoonForeastTrack
  }

  public destroy() {
    this.name = ''
    this.removeTyphoonPolygon()
    this._windCircleEntity = []
    this.removeTyphoonPointsAndLine()
    this._typhoonTrack = null
    this.removeTyphoonForeastTrack()
    this._typhoonForeastTrack = null
    this._currentPointObj = null
    this._typhoonData = null
  }

  /**
   * @description 添加台风轨迹点跟轨迹线
   * @returns typhoonPoints: 台风轨迹点
   * @returns typhoonLineEntity: 台风轨迹线
   */
  private _addTyphoonPointsAndLine() {
    const points = this._typhoonData!.points
    const lineArr: number[] = []
    const typhoonPoints: CustomDataSource = new Cesium.CustomDataSource(`TyphoonPoints-${this._typhoonData?.ename}`)
    window.viewer.dataSources.add(typhoonPoints)
    points.forEach((point) => {
      lineArr.push(point.lng)
      lineArr.push(point.lat)
      const strengthToColor = {
        '热带低压(TD)': Cesium.Color.fromCssColorString('#30fc31'),
        '热带风暴(TS)': Cesium.Color.fromCssColorString('#307efa'),
        '强热带风暴(STS)': Cesium.Color.fromCssColorString('#fffc00'),
        '台风(TY)': Cesium.Color.fromCssColorString('#ff9c00'),
        '强台风(STY)': Cesium.Color.fromCssColorString('#fb7cff'),
        '超强台风(Super TY)': Cesium.Color.fromCssColorString('#fa3030')
      }
      const color = strengthToColor[point.strong as keyof typeof strengthToColor] || Cesium.Color.WHITE
      const entity = new Cesium.Entity({
        position: Cesium.Cartesian3.fromDegrees(point.lng, point.lat),
        point: {
          pixelSize: 5,
          color: color
        }
      })
      typhoonPoints.entities.add(entity)
    })
    const typhoonLineEntity = window.viewer.entities.add({
      id: `TyphoonLine-${this._typhoonData?.ename}-${this._typhoonData?.tfbh}`,
      name: `${this._typhoonData?.ename}-${this._typhoonData?.tfbh}`,
      polyline: {
        positions: Cesium.Cartesian3.fromDegreesArray(lineArr),
        width: 3,
        clampToGround: true,
        material: Cesium.Color.RED
      }
    })
    return { typhoonPoints, typhoonLineEntity }
  }

  /**
   * @description 添加轨迹点线
   */
  public addTyphoonPointsAndLine() {
    if (this._typhoonTrack?.typhoonPoints) window.viewer.dataSources.add(this._typhoonTrack.typhoonPoints)
    if (this._typhoonTrack?.typhoonLineEntity) {
      window.viewer.entities.add(this._typhoonTrack.typhoonLineEntity)
    }
  }

  /**
   * @description 移除轨迹点线
   */
  public removeTyphoonPointsAndLine() {
    if (this._typhoonTrack?.typhoonPoints) window.viewer.dataSources.remove(this._typhoonTrack.typhoonPoints)
    if (this._typhoonTrack?.typhoonLineEntity) {
      window.viewer.entities.remove(this._typhoonTrack.typhoonLineEntity)
    }
  }

  /**
   * @description 添加预测点线
   */
  public addTyphoonForeastTrack() {
    if (this._typhoonForeastTrack?.typhoonForeastLines) {
      window.viewer.dataSources.add(this._typhoonForeastTrack.typhoonForeastLines)
    }
    if (this._typhoonForeastTrack?.typhoonForeastPoints) {
      window.viewer.dataSources.add(this._typhoonForeastTrack.typhoonForeastPoints)
    }
  }

  /**
   * @description 移除预测点线
   */
  public removeTyphoonForeastTrack() {
    if (this._typhoonForeastTrack?.typhoonForeastLines) {
      window.viewer.dataSources.remove(this._typhoonForeastTrack.typhoonForeastLines)
    }
    if (this._typhoonForeastTrack?.typhoonForeastPoints) {
      window.viewer.dataSources.remove(this._typhoonForeastTrack.typhoonForeastPoints)
    }
  }

  /**
   * @description 添加台风预测点跟预测线
   * @returns typhoonForeastPoints: 台风预测点
   * @returns typhoonForeastLines: 台风预测线
   */
  private _addTyphoonForeastPoints() {
    const forecasts = this._typhoonData?.points[this._typhoonData.points.length - 1].forecast
    const colorArr = [
      Cesium.Color.fromCssColorString('#2D12FB'),
      Cesium.Color.fromCssColorString('#15E5E7'),
      Cesium.Color.fromCssColorString('#15E74A'),
      Cesium.Color.fromCssColorString('#E76F15'),
      Cesium.Color.fromCssColorString('#15D9E7')
    ]
    const typhoonForeastPoints: CustomDataSource = new Cesium.CustomDataSource(`TyphoonForeastPoints-${this._typhoonData?.ename}`)
    const typhoonForeastLines: CustomDataSource = new Cesium.CustomDataSource(`TyphoonForeastLines-${this._typhoonData?.ename}`)
    window.viewer.dataSources.add(typhoonForeastPoints)
    window.viewer.dataSources.add(typhoonForeastLines)
    forecasts?.forEach((forecast, index) => {
      const lineArr: number[] = []
      forecast.points.forEach((point) => {
        lineArr.push(point.lng)
        lineArr.push(point.lat)
        const typhoonForeastPointEntity = new Cesium.Entity({
          position: Cesium.Cartesian3.fromDegrees(point.lng, point.lat),
          point: {
            pixelSize: 5,
            color: colorArr[index % colorArr.length]
          }
        })
        typhoonForeastPoints.entities.add(typhoonForeastPointEntity)
      })
      const typhoonForeastLineEntity = new Cesium.Entity({
        polyline: {
          positions: Cesium.Cartesian3.fromDegreesArray(lineArr),
          width: 2,
          clampToGround: true,
          material: new Cesium.PolylineDashMaterialProperty({
            color: colorArr[index % colorArr.length]
          })
        }
      })
      typhoonForeastLines.entities.add(typhoonForeastLineEntity)
    })
    return { typhoonForeastPoints, typhoonForeastLines }
  }

  /**
   * @description 添加 24 与 48 小时警戒线
   */
  static initJJLine() {
    // 24 线
    window.viewer.entities.add({
      name: '24',
      polyline: {
        positions: Cesium.Cartesian3.fromDegreesArray(
          [
            [127, 34],
            [127, 22],
            [119, 18],
            [119, 11],
            [113, 4.5],
            [105, 0]
          ].flat()
        ),
        width: 2,
        material: Cesium.Color.RED,
        clampToGround: true
      }
    })
    // 48 线
    window.viewer.entities.add({
      name: '48',
      polyline: {
        positions: Cesium.Cartesian3.fromDegreesArray(
          [
            [132, 34],
            [132, 22],
            [119, 0],
            [105, 0]
          ].flat()
        ),
        width: 2,
        material: Cesium.Color.YELLOW,
        clampToGround: true
      }
    })
    window.viewer.entities.add({
      position: Cesium.Cartesian3.fromDegrees(126.129019, 29.104287),
      label: {
        fillColor: Cesium.Color.RED,
        text: '24小时警戒线',
        font: '14pt monospace'
      }
    })
    window.viewer.entities.add({
      position: Cesium.Cartesian3.fromDegrees(132, 20),
      label: {
        fillColor: Cesium.Color.YELLOW,
        text: '48小时警戒线',
        font: '14pt monospace'
      }
    })
  }

  /**
   * @description 添加台风圈面
   */
  private _addTyphoonCircle() {
    const circles = ['circle7', 'circle10', 'circle12']
    circles.forEach((item: string) => {
      const colorMap: { [key: string]: Cesium.Color } = {
        circle7: Cesium.Color.BLUE,
        circle10: Cesium.Color.YELLOW,
        circle12: Cesium.Color.RED
      }
      const color: Color = colorMap[item] || Cesium.Color.ORANGE
      const entity = window.viewer.entities.add({
        id: `TF-Plygon-${this._typhoonData?.ename}-${this._typhoonData?.tfbh}-${item}`,
        name: `${this._typhoonData?.ename}-${this._typhoonData?.tfbh}-${item}`,
        polygon: {
          hierarchy: new Cesium.CallbackProperty(() => {
            let points: number[] = []
            if (this._currentPointObj && this._currentPointObj[item]) {
              points = getTyphoonPolygonPoints(this._currentPointObj, item)
            } else {
              points = []
            }
            return new Cesium.PolygonHierarchy(Cesium.Cartesian3.fromDegreesArray(points))
          }, false),
          material: color.withAlpha(0.2),
          extrudedHeight: 1000,
          outline: true,
          outlineColor: color,
          outlineWidth: 2
        },
        polyline: {
          positions: new Cesium.CallbackProperty(() => {
            let points: number[] = []
            if (this._currentPointObj && this._currentPointObj[item]) {
              points = getTyphoonPolygonPoints(this._currentPointObj as PointObj, item)
            } else {
              points = []
            }
            return Cesium.Cartesian3.fromDegreesArray(points)
          }, false),
          material: color,
          width: 2
        }
      })
      this._windCircleEntity.push(entity)
    })

    /**
     * @description 获取台风圈面坐标
     * @param pointObj
     * @param cNum
     * @returns 台风圈面坐标
     */
    function getTyphoonPolygonPoints(pointObj: PointObj, cNum: string) {
      const points: number[] = []
      const center = [pointObj.lon, pointObj.lat]
      const radiusList = pointObj[cNum] as Circle
      const startAngleList = [0, 90, 180, 270]
      let fx: number = 0
      let fy: number = 0
      startAngleList.forEach((startAngle, index) => {
        const radius = Object.values(radiusList)[index] / 100
        const pointNum = 90
        const endAngle = startAngle + 90
        let sin, cos, x, y, angle
        for (let i = 0; i <= pointNum; i++) {
          angle = startAngle + ((endAngle - startAngle) * i) / pointNum
          sin = Math.sin((angle * Math.PI) / 180)
          cos = Math.cos((angle * Math.PI) / 180)
          x = center[0] + radius * sin
          y = center[1] + radius * cos
          points.push(x, y)
          if (startAngle == 0 && i == 0) {
            fx = x
            fy = y
          }
        }
      })
      points.push(fx, fy)
      return points
    }
  }

  /**
   * @description 台风圈面路径移动
   */
  public moveTyphoonPolygon() {
    let iii = 0
    let kkk = 0
    this._intervalId = setInterval(() => {
      kkk = iii * 2
      this._currentPointObj = {
        lon: this._typhoonData!.points[iii].lng,
        lat: this._typhoonData!.points[iii].lat,
        circle7: {
          radius1: 350 - kkk,
          radius2: 450 - kkk,
          radius3: 400 - kkk,
          radius4: 350 - kkk
        },
        circle10: {
          radius1: 250 - kkk,
          radius2: 270 - kkk,
          radius3: 250 - kkk,
          radius4: 220 - kkk
        },
        circle12: {
          radius1: 170 - kkk,
          radius2: 150 - kkk,
          radius3: 150 - kkk,
          radius4: 170 - kkk
        }
      }
      if (iii === this._typhoonData!.points.length - 1) {
        this.stopTyphoonPolygon()
      } else {
        iii++
      }
      // iii = iii >= this._typhoonData!.points.length - 1 ? 0 : iii + 1
      if (this._windCircleEntity?.length > 0) {
        this._windCircleEntity.forEach((entity) => window.viewer.entities.remove(entity))
      }
      this._addTyphoonCircle()
    }, 200)
  }

  /**
   * @description 停止台风圈面移动
   */
  public stopTyphoonPolygon() {
    if (this._intervalId) {
      clearInterval(this._intervalId)
      this._intervalId = null
    }
  }

  /**
   * @description 移除台风圈面
   */
  public removeTyphoonPolygon() {
    if (this._intervalId) {
      clearInterval(this._intervalId)
      this._intervalId = null
    }
    if (this._windCircleEntity?.length > 0) {
      this._windCircleEntity.forEach((entity) => window.viewer.entities.remove(entity))
    }
  }
}
